package com.sjy.support.persist;

import com.github.houbb.heaven.util.io.FileUtil;
import com.github.houbb.heaven.util.lang.StringUtil;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import com.sjy.api.ICache;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 缓存持久化-AOF 持久化模式
 *
 * @author binbin.hou
 * @since 0.0.10
 */
public class CachePersistAof<K, V> extends CachePersistAdaptor<K, V> {

    private static final Log log = LogFactory.getLog(CachePersistAof.class);

    /**
     * 缓存列表
     *
     * @since 0.0.10
     */
    private final List<String> bufferList = new ArrayList<>();

    /**
     * 数据持久化路径
     *
     * @since 0.0.10
     */
    private final String dbPath;

    public CachePersistAof(String dbPath) {
        this.dbPath = dbPath;
    }

    /**
     * 持久化
     * key长度 key+value
     * 第一个空格，获取 key 的长度，然后截取
     *
     * @param cache 缓存
     */
    @Override
    public void persist(ICache<K, V> cache) {
        log.info("开始 AOF 持久化到文件");
        // 1. 创建文件
        if (!FileUtil.exists(dbPath)) {
            FileUtil.createFile(dbPath);
        }
        // 2. 持久化追加到文件中
        FileUtil.append(dbPath, bufferList);

        // 3. 清空 buffer 列表
        bufferList.clear();
        log.info("完成 AOF 持久化到文件");
    }

    public void rewrite(ICache<K, V> cache) {
        log.info("开始 AOF 重写文件");

        try {
            // 1. 读取现有的AOF文件内容
            List<String> fileContentList = FileUtil.readAllLines(dbPath);
            if (fileContentList.isEmpty()) {
                log.info("AOF文件为空，无需重写");
                return;
            }

            // 2. 使用Map来存储每个key的最新状态，实现压缩
            Map<K, String> keyLatestOperationMap = new HashMap<>();

            // 3. 解析文件内容，提取每个key的最新操作
            for (String line : fileContentList) {
                if (StringUtil.isEmpty(line)) {
                    continue;
                }

                // 解析操作类型和key（这里需要根据实际的JSON格式进行调整）
                K key = extractKeyFromJson(line);
                if (key != null) {
                    // 保存每个key的最新操作
                    keyLatestOperationMap.put(key, line);
                }
            }

            // 4. 清空buffer并重新填充压缩后的内容
            bufferList.clear();
            bufferList.addAll(keyLatestOperationMap.values());

            // 5. 重写文件，只保留每个key的最新状态
            FileUtil.write(dbPath, bufferList);

            log.info("完成 AOF 重写文件，原始记录数: {}, 压缩后记录数: {}",
                    fileContentList.size(), bufferList.size());
        } catch (Exception e) {
            log.error("AOF 重写文件失败", e);
            throw new RuntimeException("AOF 重写失败", e);
        }
    }

    // 从JSON字符串中提取key的辅助方法
// 需要根据实际的JSON格式进行实现
    @SuppressWarnings("unused")
    private K extractKeyFromJson(String jsonLine) {
        try {
            // 示例实现，需要根据实际JSON格式调整
            // 假设JSON格式为: {"operation":"SET","key":"keyName","value":"value"}
            if (jsonLine.contains("\"key\":\"")) {
                int keyStart = jsonLine.indexOf("\"key\":\"") + 7;
                int keyEnd = jsonLine.indexOf("\"", keyStart);
                if (keyStart > 6 && keyEnd > keyStart) {
                    String keyStr = jsonLine.substring(keyStart, keyEnd);
                    // 这里需要根据实际的key类型进行转换
                    // 由于泛型擦除，这里只是一个示例
                    return (K) keyStr;
                }
            }
        } catch (Exception e) {
            log.warn("解析key失败: {}", jsonLine, e);
        }
        return null;
    }

    @Override
    public long delay() {
        return 1;
    }

    @Override
    public long period() {
        return 1;
    }

    @Override
    public TimeUnit timeUnit() {
        return TimeUnit.SECONDS;
    }

    /**
     * 添加文件内容到 buffer 列表中
     *
     * @param json json 信息
     * @since 0.0.10
     */
    public void append(final String json) {
        if (StringUtil.isNotEmpty(json)) {
            bufferList.add(json);
        }
    }

}